package com.api.config;

import cn.dev33.satoken.exception.NotLoginException;
import com.api.dispose.enums.ReturnCodeEnums;
import com.api.dispose.exception.AppException;
import com.api.dispose.exception.LoginException;
import com.api.dispose.vo.ResultDataVo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * 全局返回结果包装类以及常见异常记录
 *
 * @author 李大牛家的牛 (scafel@163.com)
 * @product IntelliJ IDEA
 * @createDate 2025/5/20-15:16
 * @description TODO...
 **/
@Slf4j
@RestControllerAdvice
public class ResponseConfig  implements ResponseBodyAdvice<Object> {


    private final ObjectMapper objectMapper;

    public ResponseConfig(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }


    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }


    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof String) {
            try {
                return objectMapper.writeValueAsString(ResultDataVo.success(body));
            } catch (JsonProcessingException ex) {
                return ResultDataVo.fail(ReturnCodeEnums.RC500.getCode(), ReturnCodeEnums.RC500.getMessage());
            }
        } else if (body instanceof ResultDataVo) {
            return body;
        } else {
            return ResultDataVo.success(body);
        }
    }


    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(AppException.class)
    @ResponseBody
    public ResultDataVo<Object> appException(AppException ex) {
        log.error("appException: { }", ex);
        return ResultDataVo.fail(ex.getCode(), ex.getMessage());
    }

    @ExceptionHandler({LoginException.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ResultDataVo<Object> loginException(LoginException ex) {
        log.error("loginException:code =>{} ex =>{}", ex.getCode(), ex.getMessage());
        return ResultDataVo.fail(ReturnCodeEnums.RC201.getCode(), ex.getMessage());
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseBody
    public ResultDataVo<Object> methodArgumentNotValidException(MethodArgumentNotValidException ex) {
        log.error("methodArgumentNotValidException: { }", ex);
        return ResultDataVo.fail(ReturnCodeEnums.RC203.getCode(), ex.getBindingResult().getAllErrors().get(0).getDefaultMessage());
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({HttpMessageNotReadableException.class})
    @ResponseBody
    public ResultDataVo<Object> httpMessageNotReadableException(HttpMessageNotReadableException ex) {
        log.error("httpMessageNotReadableException: { }", ex);
        return ResultDataVo.fail(ReturnCodeEnums.RC203.getCode(), ReturnCodeEnums.RC203.getMessage());
    }

    @ExceptionHandler(NotLoginException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ResultDataVo<Object> notLoginException(NotLoginException ex) {
        log.error("notLoginException: ex =>{}", ex.getMessage());
        return ResultDataVo.fail(ReturnCodeEnums.RC201.getCode(), "未登录，请先登录!");
    }

    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ResultDataVo<Object> exception(Exception ex) {
        log.error("exception: { }", ex);
        return ResultDataVo.fail(ReturnCodeEnums.RC500.getCode(), ReturnCodeEnums.RC500.getMessage() );
    }
}
